package org.eclipse.soc.ide4edu.assignment.wizards;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.soc.ide4edu.assignment.operations.AssignmentZipOperation;
import org.eclipse.soc.ide4edu.assignment.operations.UploadOperation;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.browser.IWebBrowser;

public class UploadWizard extends Wizard implements INewWizard {

	IStructuredSelection selection;
	IWorkbench workbench;
	UploadWizardPage1 uploadPage;
	UploadWizardPage2 loginInfo;

	AssignmentZipOperation zipOperation;

	public UploadWizard() {
		super();

	}

	@Override
	public void addPages() {
		uploadPage = new UploadWizardPage1(selection);
		addPage(uploadPage);
		loginInfo = new UploadWizardPage2(selection);
		addPage(loginInfo);

	}

	/**
	 * This method is called when the user chooses to authenticate through
	 * eclipse. A new instance of
	 * {@link org.eclipse.soc.ide4edu.assignment.operations.UploadOperation} is
	 * created and authentication and upload is done by that class.
	 */
	private void authenticateThruEclipse() {
		try {

			String zipPath = zipOperation.getSavePath();
			UploadOperation op = new UploadOperation(uploadPage
					.getContainerName(), uploadPage.getFinalURL().toString(),
					zipPath);
			op.authenticate(loginInfo.getUsername(), loginInfo.getPassword());
			String uploadURL = getUploadURL();
			op.uploadFile(uploadURL);

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * Calls methods based on the return code of the user's authentication choice in {@link org.eclipse.soc.ide4edu.assignment.wizards.UploadWizardPage1}
	 * @throws PartInitException
	 * @throws CoreException
	 */
	private void executeUserChoice() throws PartInitException, CoreException {
		String choice = loginInfo.getUserChoice();
		if (choice == "browser") {
			openBrowser();
			return;
		}
		if (choice == "eclipse") {
			authenticateThruEclipse();
			return;
		}
	}

	/**
	 * Computes the URL where the Files are to be uploaded based on the Server name and Address. 
	 * @return A String representation of the URL
	 */
	protected String getUploadURL() {

		String url = null;

		try {
			if (uploadPage.getServerName() == "Moodle") {
				url = uploadPage.getServerURL() + "/files/index.php?id="
						+ loginInfo.getCourseIDParam();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return url;
	}

	/**
	 * Opens a Dialog showing the Exception's stack trace
	 * @param e The instance of the Exception
	 */
	private void handleException(Exception e) {
		IStatus status = new Status(4, "Browser Exception", -1,
				"An Exception has Occured !", e);
		ErrorDialog error = new ErrorDialog(getShell(), "Error",
				e.getMessage(), status, 0);
		error.create();
		error.open();
	}

	/** Initializes the workbench and selection
	 *  
	 */
	public void init(IWorkbench workbench, IStructuredSelection selection) {

		this.workbench = workbench;
		this.selection = selection;
	}

	/** Opens a Browser inside the Eclipse WorkBench. This is triggered when Authentication is done through browser 
	 * 
	 * @throws PartInitException
	 * @throws CoreException
	 */
	private void openBrowser() throws PartInitException, CoreException {
		IWebBrowser browser = PlatformUI.getWorkbench().getBrowserSupport()
				.createBrowser((1 << 5) | (1 << 1) | (1 << 2), "Assignment",
						"Assignment", "Assignment");
		browser.openURL(uploadPage.getFinalURL());

	}

	@Override
	/**
	 * Calls method to Zip the assignment First and authenticate with the server according to the user's choice. 
	 */
	public boolean performFinish() {

		boolean status = performZipOperation();

		if (status == false)
			return false;

		try {
			executeUserChoice();
		} catch (PartInitException e) {
			e.printStackTrace();
		} catch (CoreException e) {
			e.printStackTrace();
		}
		return true;

	}

	/**
	 * Zipping is done by {@link org.eclipse.soc.ide4edu.assignment.operations.AssignmentZipOperation}
	 * @return true if Zipping was successful.
	 */
	protected boolean performZipOperation() {

		zipOperation = new AssignmentZipOperation();
		IRunnableWithProgress op = new IRunnableWithProgress() {
			public void run(final IProgressMonitor monitor)
					throws InvocationTargetException {
				try {
					getShell().getDisplay().asyncExec(new Runnable() {
						public void run() {
							String fullPath = uploadPage
									.getAssignmentResource().getLocation()
									.toString();

							try {
								monitor.beginTask("working...", 100);
								zipOperation.saveAsZIP(uploadPage
										.getAssignmentName(), fullPath,
										getShell(), monitor);

							} catch (IOException e) {
								handleException(e);
							} catch (PartInitException e) {
								handleException(e);
							} catch (CoreException e) {
								handleException(e);
							}

						}
					});

				} finally {
					monitor.done();
				}
			}
		};

		try {
			new ProgressMonitorDialog(getShell()).run(true, false, op);
		} catch (InterruptedException e) {
			return false;
		} catch (InvocationTargetException e) {
			Throwable realException = e.getTargetException();
			MessageDialog.openError(getShell(), "Error", realException
					.getMessage());
			return false;
		}

		return true;

	}

}
